/*
 * misc/bxstats.cc
 * $Id: bxstats.cc 10932 2012-06-20 19:20:52Z xtong $
 *
 * print emulator internal statistics.
 *
 */

#include <stdio.h>
#include <sys/shm.h>  // for shmxxx.

#include "../bochs.h"
#include "../cpu/cpu.h"
#include "../cpu/stats.h"

/// global output file of printing.
FILE *out_file = 0;

#define PRINT_TO_FILE fprintf

bxCPUControl_c *map(void)
{
  Bit32u id = shmget(SHARED_MEM_KEY, 
                     sizeof(bxCPUControl_c), 
                     IPC_CREAT | 
                     S_IRUSR   | 
                     S_IWUSR);

  if (id == -1) 
  {
     PRINT_TO_FILE(out_file, "SHMGET: shmget failed"); 
     exit(1); 
  } 
  else 
  {
     PRINT_TO_FILE(out_file, "SHMGET: shmget returned 0x%x\n", id); 
  }

  return (bxCPUControl_c*)shmat(id, 0, 0);
}

void unmap(void *address)
{
  // detach the debug memory.
  shmdt(address);
}

void print_help(void) 
{
  PRINT_TO_FILE(out_file, "bxstats - a tool to dump statistics of the emulator\n");
  PRINT_TO_FILE(out_file, "-h           help message\n");
  PRINT_TO_FILE(out_file, "-s           the base address of the mapped shared segment\n");
  PRINT_TO_FILE(out_file, "-t           print all the collected traces\n");
  PRINT_TO_FILE(out_file, "-c           the suffix of the memory key (default to 0)\n");
  PRINT_TO_FILE(out_file, "-f           flush the code cache\n");
  PRINT_TO_FILE(out_file, "-n           do not cache the code cache\n");
}

void flush_cc(bxCPUControl_c *address)
{
  // tell the emulator to flush code cache.
  PRINT_TO_FILE(out_file, "Flushing the emulator code cache\n");
  address->flushcc = 1;
}

void no_cache(bxCPUControl_c *address)
{
  // tell the emulator to flush code cache.
  PRINT_TO_FILE(out_file, "No cache the emulator code cache\n");
  address->nocache = 1;
}

int main(int argc, char **argv) 
{
  // default output file is standard out.
  out_file = fopen("/dev/tty", "w");
  if (!out_file) 
  {
     PRINT_TO_FILE(out_file, "unable to open output file");
     exit(-1);
  }

  if (argc < 2) 
  {
     print_help();
     exit(0);
  }

  // map in the shared memory.
  bxCPUControl_c *address = map();

  Bit32u phelp = 0;
  Bit32u ptrace = 0;
  Bit32u flushcc = 0;
  Bit32u nocache = 0;

  Bit32u idx = 0;
  for (idx = 1; idx < argc; idx++) 
  {
    if (!strncmp(argv[idx], "-h", strlen("-h"))) 
    {
      phelp = 1;
    }
    else if (!strncmp(argv[idx], "-t", strlen("-t"))) 
    {
      ptrace = 1;
    }
    else if (!strncmp(argv[idx], "-s", strlen("-s"))) 
    {
    }
    else if (!strncmp(argv[idx], "-f", strlen("-f"))) 
    {
      // flush code cache.
      flushcc = 1;
    }
    else if (!strncmp(argv[idx], "-n", strlen("-n"))) 
    {
      // set no cache.
      nocache = 1;
    }
    else if (!strncmp(argv[idx], "-c", strlen("-c"))) 
    {
    }
    else 
    {
      // unrecognized option.
      phelp = 1;
    }
  }

  // done with command line parsing. print what is needed.
  if (phelp)    print_help();
  if (flushcc) flush_cc(address);
  if (nocache) no_cache(address);

  // unmap the debug memory.
  unmap(address);

  return 0;
}
